import { MatchFormat } from "../utils";

export type annotationRuleType = ["ANNOTATION", [variableNameRuleType, [calcRuleType[] | "EMPTY"]][]];
export type genericRuleType = ["GENERIC", variableNameRuleType[]];

export type arrayRuleType = ["ARRAY", calcRuleType[]];
export type booleanRuleType = ["BOOLEAN", `${boolean}`];
export type classAttrRuleType = ["CLASS_ATTR", annotationRuleType, ["public" | "private" | "protected"] | [], exportValueRuleType];
export type classRuleType = ["CLASS", annotationRuleType, variableNameRuleType | [], genericRuleType, classAttrRuleType[]];
export type functionReturnRuleType = ["FUNCTION_RETURN", calcRuleType];
export type functionRuleType = ["FUNCTION", variableNameRuleType | [], genericRuleType, [variableNameRuleType, typeCalcRuleType | []][], (functionReturnRuleType | executeDataRuleType)[]]
export type hashMapRuleType = ["HASH_MAP", [variableNameRuleType, calcRuleType][]];
export type interfaceRuleType = ["INTERFACE", variableNameRuleType | [], genericRuleType, typeMapRuleType];
export type numberRuleType = ["NUMBER", `${number}`];
export type stringRuleType = ["STRING", string];
export type structRuleType = ["STRUCT", variableNameRuleType | [], genericRuleType, typeMapRuleType];
export type xmlRuleType = never;
export type dataRuleType = variableNameRuleType | numberRuleType | stringRuleType | booleanRuleType | functionRuleType | classRuleType | arrayRuleType | structRuleType | hashMapRuleType;

export type unaryRuleType = ["UNARY", ["!" | "~" | "-" | "++" | "--" | "new" | "default"] | [], dataRuleType];
export type calcCalcRuleType = ["CALC_CALC", "+" | "-" | "*" | "/" | "^" | "%" | ">" | "<" | "&" | "|" | ">>" | "<<" | ">=" | "<=" | "==" | "!=" | "&&" | "||", unaryRuleType | calcRuleType];
export type calcParamsRuleType = ["CALC_PARAMS", calcRuleType[]];
export type calcAttrRuleType = ["CALC_ATTR", variableNameRuleType];
export type calcIndexRuleType = ["CALC_INDEXS", calcRuleType];
export type calcTernaryRuleType = ["CALC_TERNARY", calcRuleType, calcRuleType];
export type calcPPRuleType = ["CALC_PP"];
export type calcRRRuleType = ["CALC_RR"];
export type calcRightRuleType = (calcCalcRuleType | calcParamsRuleType | calcAttrRuleType | calcIndexRuleType | calcTernaryRuleType | calcPPRuleType | calcRRRuleType);
export type calcRuleType = ["CALC", unaryRuleType | calcRuleType, calcRightRuleType[]];
export type semicolonDataRuleType = ["SEMICOLON", variableCreatedlRuleType | calcRuleType | typeCreatedRuleType];
export type executeDataRuleType = semicolonDataRuleType | functionRuleType | classRuleType | interfaceRuleType | structRuleType | proceduralRuleType;

export type exportSemicolonRuleType = ["SEMICOLON", variableCreatedlRuleType | typeCreatedRuleType | hashMapRuleType];
export type exportValueRuleType = exportSemicolonRuleType | functionRuleType | classRuleType | interfaceRuleType | structRuleType;
export type exportRuleType = ["EXPORT", ["default"] | [], exportValueRuleType];
export type importVarRuleType = [variableNameRuleType, variableNameRuleType | []];
export type importRuleType = ["IMPORT", [importVarRuleType | [], importVarRuleType[]] | [], stringRuleType];
export type exportDataRuleType = exportRuleType | importRuleType | executeDataRuleType;

export type doWhilelRuleType = ["DO_WHILE", executeRuleType, calcRuleType];
export type forRuleType = ["FOR", [variableCreatedlRuleType, calcRuleType, calcRuleType | variableCreatedlRuleType], executeRuleType];
export type ifRuleType = ["IF", calcRuleType, executeRuleType, ["ELSE_IF", calcRuleType, executeRuleType][], ["ELSE", executeRuleType] | []];
export type loopRuleType = ["LOOP", executeRuleType];
export type tryCatchRuleType = ["TRY", executeRuleType, ["TRY_CATCH", variableNameRuleType, executeRuleType][], ["TRY_FINALLY", executeRuleType] | []];
export type whilelRuleType = ["WHILE", calcRuleType, executeRuleType];
export type proceduralRuleType = whilelRuleType | doWhilelRuleType | loopRuleType | forRuleType | ifRuleType | tryCatchRuleType;

export type typeArrayRuleType = ["TYPE_ARRAY", typeCalcRuleType[]];
export type typeCalcRuleType = ["TYPE_CALC", typeDataRuleType | typeCalcRuleType, ["&" | "|", typeDataRuleType | typeCalcRuleType][]];
export type typeCreatedRuleType = ["TYPE_CREATED", variableNameRuleType, genericRuleType, "=", typeCalcRuleType];
export type typeMapRuleType = ["TYPE_MAP", [variableNameRuleType, typeCalcRuleType][]];
export type typeNameRuleType = ["TYPE_NAME", variableNameRuleType, [typeNameRuleType[]] | []];
export type typeDataRuleType = numberRuleType | stringRuleType | booleanRuleType | typeNameRuleType | typeMapRuleType | typeArrayRuleType;

export type variableCreatedlRuleType = ["VAR_CREATED", ["const" | "var" | "final" | "let" | "static" | "bind"] | [], variableDataRuleType, typeCalcRuleType | [], "=" | "+=" | "-=" | "*=" | "/=" | "%=" | ">>=" | "<<=" | "&=" | "^=" | "|=", calcRuleType];
export type variableListRuleType = ["VAR_LIST", variableNameRuleType[]];
export type variableMapRuleType = ["VAR_MAP", ([variableNameRuleType, variableNameRuleType] | [variableNameRuleType])[]];
export type variableNameRuleType = ["VAR_NAME", string];
export type variableDataRuleType = variableNameRuleType | variableListRuleType | variableMapRuleType;

export type executeRuleType = executeDataRuleType[];
export type exportExecuteRuleType = exportDataRuleType[];

export type FormatFunc = (rule: MatchFormat) => string;

export type FormatInfoFunc<T> = (rule: T, format: FormatFunc) => string;

export interface FormatInfo<T extends MatchFormat> {
	type: string;
	handle: FormatInfoFunc<T>;
}

export type FormatMap = { [T: string]: FormatInfoFunc<any>; };

const formatMap: FormatMap = {};

export const AddFormatFunc = function <T extends MatchFormat>(formatInfo: FormatInfo<T>) {
	formatMap[formatInfo.type] = formatInfo.handle;
}

export const GetFormatMap = function () {
	return formatMap;
};
